#include "gtkgridview.h"
+#include "gtkbitset.h"
#include "gtkintl.h"
#include "gtklistbaseprivate.h"
#include "gtklistitemfactory.h"
return TRUE;
}
+static GtkBitset *
+gtk_grid_view_get_items_in_rect (GtkListBase *base,
+ const GdkRectangle *rect)
+{
+ GtkGridView *self = GTK_GRID_VIEW (base);
+ guint first_row, last_row, first_column, last_column, n_items;
+ GtkBitset *result;
+
+ result = gtk_bitset_new_empty ();
+
+ n_items = gtk_list_base_get_n_items (base);
+ if (n_items == 0)
+ return result;
+
+ first_column = floor (rect->x / self->column_width);
+ last_column = floor ((rect->x + rect->width) / self->column_width);
+ if (!gtk_grid_view_get_cell_at_y (self, rect->y, &first_row, NULL, NULL))
+ first_row = rect->y < 0 ? 0 : n_items - 1;
+ if (!gtk_grid_view_get_cell_at_y (self, rect->y + rect->height, &last_row, NULL, NULL))
+ last_row = rect->y < 0 ? 0 : n_items - 1;
+
+ gtk_bitset_add_rectangle (result,
+ first_row + first_column,
+ last_column - first_column + 1,
+ (last_row - first_row) / self->n_columns + 1,
+ self->n_columns);
+
+ return result;
+}
+
static guint
gtk_grid_view_move_focus_along (GtkListBase *base,
guint pos,
list_base_class->list_item_augment_func = cell_augment;
list_base_class->get_allocation_along = gtk_grid_view_get_allocation_along;
list_base_class->get_allocation_across = gtk_grid_view_get_allocation_across;
+ list_base_class->get_items_in_rect = gtk_grid_view_get_items_in_rect;
list_base_class->get_position_from_allocation = gtk_grid_view_get_position_from_allocation;
list_base_class->move_focus_along = gtk_grid_view_move_focus_along;
list_base_class->move_focus_across = gtk_grid_view_move_focus_across;
double start_align_across; /* alignment in horizontal direction */
double start_align_along; /* alignment in vertical direction */
- GtkBitset *active;
double pointer_x, pointer_y; /* mouse coordinates in widget space */
gboolean modify;
gboolean extend;
gtk_widget_class_add_binding_action (widget_class, GDK_KEY_backslash, GDK_CONTROL_MASK, "list.unselect-all", NULL);
}
-static void gtk_list_base_update_rubberband_selection (GtkListBase *self);
-
static gboolean
autoscroll_cb (GtkWidget *widget,
GdkFrameClock *frame_clock,
}
}
-void
-gtk_list_base_allocate_rubberband (GtkListBase *self)
+static GtkBitset *
+gtk_list_base_get_items_in_rect (GtkListBase *self,
+ const GdkRectangle *rect)
+{
+ return GTK_LIST_BASE_GET_CLASS (self)->get_items_in_rect (self, rect);
+}
+
+static gboolean
+gtk_list_base_get_rubberband_coords (GtkListBase *self,
+ GdkRectangle *rect)
{
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
- GtkRequisition min_size;
int x1, x2, y1, y2;
- int offset_x, offset_y;
if (!priv->rubberband)
- return;
+ return FALSE;
if (priv->rubberband->start_tracker == NULL)
{
priv->rubberband->pointer_x, priv->rubberband->pointer_y,
&x2, &y2);
+ rect->x = MIN (x1, x2);
+ rect->y = MIN (y1, y2);
+ rect->width = ABS (x1 - x2) + 1;
+ rect->height = ABS (y1 - y2) + 1;
+
+ return TRUE;
+}
+
+void
+gtk_list_base_allocate_rubberband (GtkListBase *self)
+{
+ GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
+ GtkRequisition min_size;
+ GdkRectangle rect;
+ int offset_x, offset_y;
+
+ if (!gtk_list_base_get_rubberband_coords (self, &rect))
+ return;
+
gtk_widget_get_preferred_size (priv->rubberband->widget, &min_size, NULL);
+ rect.width = MAX (min_size.width, rect.width);
+ rect.height = MAX (min_size.height, rect.height);
gtk_list_base_get_adjustment_values (self, OPPOSITE_ORIENTATION (priv->orientation), &offset_x, NULL, NULL);
gtk_list_base_get_adjustment_values (self, priv->orientation, &offset_y, NULL, NULL);
+ rect.x -= offset_x;
+ rect.y -= offset_y;
gtk_list_base_size_allocate_child (self,
priv->rubberband->widget,
- MIN (x1, x2) - offset_x,
- MIN (y1, y2) - offset_y,
- MAX (min_size.width, ABS (x1 - x2) + 1),
- MAX (min_size.height, ABS (y1 - y2) + 1));
+ rect.x, rect.y, rect.width, rect.height);
}
static void
priv->rubberband->widget = gtk_gizmo_new ("rubberband",
NULL, NULL, NULL, NULL, NULL, NULL);
gtk_widget_set_parent (priv->rubberband->widget, GTK_WIDGET (self));
- priv->rubberband->active = gtk_bitset_new_empty ();
}
static void
if (model != NULL)
{
GtkBitset *selected, *mask;
+ GdkRectangle rect;
+ GtkBitset *rubberband_selection;
+
+ if (!gtk_list_base_get_rubberband_coords (self, &rect))
+ return;
+
+ rubberband_selection = gtk_list_base_get_items_in_rect (self, &rect);
if (priv->rubberband->extend)
{
- mask = gtk_bitset_ref (priv->rubberband->active);
+ mask = gtk_bitset_ref (rubberband_selection);
}
else
{
if (priv->rubberband->modify)
selected = gtk_bitset_new_empty ();
else
- selected = gtk_bitset_ref (priv->rubberband->active);
+ selected = gtk_bitset_ref (rubberband_selection);
gtk_selection_model_set_selection (model, selected, mask);
gtk_bitset_unref (selected);
gtk_bitset_unref (mask);
+ gtk_bitset_unref (rubberband_selection);
}
gtk_list_item_tracker_free (priv->item_manager, priv->rubberband->start_tracker);
g_clear_pointer (&priv->rubberband->widget, gtk_widget_unparent);
- g_clear_pointer (&priv->rubberband->active, gtk_bitset_unref);
g_free (priv->rubberband);
priv->rubberband = NULL;
remove_autoscroll (self);
-
- gtk_widget_queue_draw (GTK_WIDGET (self));
}
static void
-gtk_list_base_update_rubberband (GtkListBase *self,
- double x,
- double y)
+gtk_list_base_update_rubberband_selection (GtkListBase *self)
{
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
+ GtkListItemManagerItem *item;
+ GdkRectangle rect;
+ guint pos;
+ GtkBitset *rubberband_selection;
- if (!priv->rubberband)
+ if (!gtk_list_base_get_rubberband_coords (self, &rect))
return;
- priv->rubberband->pointer_x = x;
- priv->rubberband->pointer_y = y;
-
- gtk_list_base_update_rubberband_selection (self);
+ rubberband_selection = gtk_list_base_get_items_in_rect (self, &rect);
- update_autoscroll (self, x, y);
+ pos = 0;
+ for (item = gtk_list_item_manager_get_first (priv->item_manager);
+ item != NULL;
+ item = gtk_rb_tree_node_get_next (item))
+ {
+ if (item->widget)
+ {
+ if (gtk_bitset_contains (rubberband_selection, pos))
+ gtk_widget_set_state_flags (item->widget, GTK_STATE_FLAG_ACTIVE, FALSE);
+ else
+ gtk_widget_unset_state_flags (item->widget, GTK_STATE_FLAG_ACTIVE);
+ }
+
+ pos += item->n_items;
+ }
- gtk_widget_queue_draw (GTK_WIDGET (self));
+ gtk_bitset_unref (rubberband_selection);
}
static void
-gtk_list_base_update_rubberband_selection (GtkListBase *self)
+gtk_list_base_update_rubberband (GtkListBase *self,
+ double x,
+ double y)
{
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
- GdkRectangle rect;
- GdkRectangle alloc;
- GtkListItemManagerItem *item;
- gtk_list_base_allocate_rubberband (self);
- gtk_widget_get_allocation (priv->rubberband->widget, &rect);
-
- for (item = gtk_list_item_manager_get_first (priv->item_manager);
- item != NULL;
- item = gtk_rb_tree_node_get_next (item))
- {
- guint pos;
+ if (!priv->rubberband)
+ return;
- if (!item->widget)
- continue;
+ priv->rubberband->pointer_x = x;
+ priv->rubberband->pointer_y = y;
- pos = gtk_list_item_manager_get_item_position (priv->item_manager, item);
+ gtk_list_base_update_rubberband_selection (self);
- gtk_widget_get_allocation (item->widget, &alloc);
+ update_autoscroll (self, x, y);
- if (gdk_rectangle_intersect (&rect, &alloc, &alloc))
- {
- gtk_bitset_add (priv->rubberband->active, pos);
- gtk_widget_set_state_flags (item->widget, GTK_STATE_FLAG_ACTIVE, FALSE);
- }
- else
- {
- gtk_bitset_remove (priv->rubberband->active, pos);
- gtk_widget_unset_state_flags (item->widget, GTK_STATE_FLAG_ACTIVE);
- }
- }
+ gtk_widget_queue_allocate (GTK_WIDGET (self));
}
static void
#include "gtklistview.h"
+#include "gtkbitset.h"
#include "gtkintl.h"
#include "gtklistbaseprivate.h"
#include "gtklistitemmanagerprivate.h"
return TRUE;
}
+static GtkBitset *
+gtk_list_view_get_items_in_rect (GtkListBase *base,
+ const cairo_rectangle_int_t *rect)
+{
+ GtkListView *self = GTK_LIST_VIEW (base);
+ guint first, last, n_items;
+ GtkBitset *result;
+ ListRow *row;
+
+ result = gtk_bitset_new_empty ();
+
+ n_items = gtk_list_base_get_n_items (base);
+ if (n_items == 0)
+ return result;
+
+ row = gtk_list_view_get_row_at_y (self, rect->y, NULL);
+ if (row)
+ first = gtk_list_item_manager_get_item_position (self->item_manager, row);
+ else
+ first = rect->y < 0 ? 0 : n_items - 1;
+ row = gtk_list_view_get_row_at_y (self, rect->y + rect->height, NULL);
+ if (row)
+ last = gtk_list_item_manager_get_item_position (self->item_manager, row);
+ else
+ last = rect->y < 0 ? 0 : n_items - 1;
+
+ gtk_bitset_add_range_closed (result, first, last);
+ return result;
+}
+
static guint
gtk_list_view_move_focus_along (GtkListBase *base,
guint pos,
list_base_class->list_item_augment_func = list_row_augment;
list_base_class->get_allocation_along = gtk_list_view_get_allocation_along;
list_base_class->get_allocation_across = gtk_list_view_get_allocation_across;
+ list_base_class->get_items_in_rect = gtk_list_view_get_items_in_rect;
list_base_class->get_position_from_allocation = gtk_list_view_get_position_from_allocation;
list_base_class->move_focus_along = gtk_list_view_move_focus_along;
list_base_class->move_focus_across = gtk_list_view_move_focus_across;